<template>
  <div class="chat_box">
    <div class="chat_content" ref="content" @scroll="handleScroll">
      <div class="items" ref="items" :style="{ top: itemsTop }">
        <div
          v-for="(item, idx) in showData"
          :key="idx"
          :style="{
            height: size + 'px',
            backgroundColor: '#eee',
          }"
        >
          <span>{{ item.nickname }}:</span>
          <span>{{ item.msg }}</span>
        </div>
      </div>
      <div class="bar" :style="{ height: barHeight }" ref="bar"></div>
    </div>
    <div>
      <input type="text" v-model.trim="msg" />
      <button @click="sendMsg">发送消息</button>
    </div>
  </div>
</template>

<script>
//虚拟列表demo
export default {
  data() {
    return {
      msg: 1,
      msgList: [],
      start: "", //开始位置
      end: "", //结束位置
      msgNum: "", //渲染条数
      size: 50, //每一条的高度
      itemsTop: 0,
    };
  },
  mounted() {
    //初始化开始位置及结束位置
    this.handleScroll();
  },
  methods: {
    //发送消息
    sendMsg() {
      if (!this.msg) {
        return;
      }
      this.msg++;
      this.msgList.push({
        nickname: "laoxiao",
        msg: this.msg,
      });
      //数据更新后把滚动条滚到最底部
      this.$nextTick(() => {
        this.$refs["content"].scrollTop = this.$refs["content"].scrollHeight;
        this.getItemsTop();
      });
    },
    //容器滚动事件
    handleScroll() {
      //获取容器顶部滚动的尺寸
      const scrollTop = this.$refs["content"].scrollTop;
      //计算卷去的数据条数，用计算的结果作为获取数据的起始和结束下标
      //起始下标就是卷去的数据条数，向下取整
      this.start = Math.floor(scrollTop / this.size);
      //结束的下标就是起始的下标加上要展示的数据条数
      this.end = this.start + this.shownumber;
      this.getItemsTop();
    },
    //设置展示区的top值，父元素被卷去的高度就是item的定位top值
    getItemsTop() {
      if (this.msgList.length <= this.shownumber) {
        return false;
      }
      this.itemsTop = this.$refs["content"].scrollTop + "px";
    },
  },
  computed: {
    //最终筛选的数据
    showData() {
      return this.msgList.slice(this.start, this.end);
    },
    //计算一页展示条数
    shownumber() {
      //可视区高度除每一条的高度向上取整为每次展示的条数
      return Math.ceil(this.$refs["content"].clientHeight / this.size);
    },
    //撑开容器的高度
    barHeight() {
      //每一条的高度 * 总条数为撑开的高度，出现滚动条
      return this.size * this.msgList.length + "px";
    },
  },
};
</script>

<style lang="less" scoped>
.chat_box {
  width: 300px;
  margin: 50px auto;
  .chat_content {
    position: relative;
    width: 300px;
    height: 500px;
    overflow-y: scroll;
    background-color: #ccc;
    .items {
      position: absolute;
      top: 0;
      z-index: 2;
      width: 100%;
    }
  }
}
.bar {
  background-color: #ccc;
}
</style>